const request = require('supertest');
const express = require('express');
const factorsRoutes = require('../../routes/factors');
const mockQuery = jest.fn();
jest.mock('../../config/database', () => ({
  query: (...args) => mockQuery(...args)
}));
jest.mock('../../middleware/auth', () => ({
  authenticateToken: (req, res, next) => { req.user = { id: 1, role: 'user' }; next(); },
  checkRole: () => (req, res, next) => next()
}));

describe('Factors Routes', () => {
  let app;
  beforeEach(() => {
    app = express();
    app.use(express.json());
    app.use('/factors', factorsRoutes);
    mockQuery.mockReset();
  });

  test('GET /factors 正常', async () => {
    mockQuery.mockResolvedValueOnce([{ total: 1 }]);
    mockQuery.mockResolvedValueOnce([{ id: 1, name: '因子A' }]);
    const res = await request(app).get('/factors');
    expect(res.status).toBe(200);
    expect(res.body.data[0].name).toBe('因子A');
  });

  test('GET /factors 500', async () => {
    mockQuery.mockRejectedValueOnce(new Error('db error'));
    const res = await request(app).get('/factors');
    expect(res.status).toBe(500);
  });

  test('POST /factors 正常', async () => {
    mockQuery.mockResolvedValueOnce({ insertId: 1 });
    const res = await request(app).post('/factors').send({ name: '新因子', description: '', formula: '', category: '', baseFactors: [] });
    expect([201, 500]).toContain(res.status);
  });

  test('POST /factors 创建（带 baseFactors）', async () => {
    mockQuery.mockResolvedValueOnce({ insertId: 2 });
    mockQuery.mockResolvedValue({});
    const res = await request(app).post('/factors').send({ name: '新因子', description: '', formula: '', category: '', baseFactors: [{ id: 1, weight: 0.5 }] });
    expect([201, 500]).toContain(res.status);
  });

  test('POST /factors 缺少参数', async () => {
    const res = await request(app).post('/factors').send({});
    expect([400, 500]).toContain(res.status);
  });

  test('POST /factors 500', async () => {
    mockQuery.mockRejectedValueOnce(new Error('db error'));
    const res = await request(app).post('/factors').send({ name: '新因子', description: '', formula: '', category: '', baseFactors: [] });
    expect(res.status).toBe(500);
  });

  test('GET /factors/:id 返回单个因子', async () => {
    mockQuery.mockResolvedValueOnce([{ id: 1, name: '因子A' }]);
    const res = await request(app).get('/factors/1');
    expect(res.status).toBe(200);
    expect(res.body[0].id).toBe(1);
  });

  test('GET /factors/:id 返回404', async () => {
    mockQuery.mockResolvedValueOnce([]);
    const res = await request(app).get('/factors/999');
    expect(res.status).toBe(404);
  });

  test('PUT /factors/:id 更新因子', async () => {
    mockQuery.mockResolvedValueOnce({ affectedRows: 1 });
    const res = await request(app).put('/factors/1').send({ name: '更新因子' });
    expect([200, 404]).toContain(res.status);
  });

  test('DELETE /factors/:id 删除因子', async () => {
    mockQuery.mockResolvedValueOnce({ affectedRows: 1 });
    const res = await request(app).delete('/factors/1');
    expect([200, 404]).toContain(res.status);
  });

  test('PUT /factors/:id 更新不存在的因子', async () => {
    mockQuery.mockResolvedValueOnce({ affectedRows: 0 });
    const res = await request(app).put('/factors/999').send({ name: '不存在' });
    expect(res.status).toBe(404);
  });

  test('DELETE /factors/:id 删除不存在的因子', async () => {
    mockQuery.mockResolvedValueOnce({ affectedRows: 0 });
    const res = await request(app).delete('/factors/999');
    expect(res.status).toBe(404);
  });

  test('PUT /factors/:id 数据库异常', async () => {
    mockQuery.mockRejectedValueOnce(new Error('db error'));
    const res = await request(app).put('/factors/1').send({ name: '异常' });
    expect([500, 404]).toContain(res.status);
  });

  test('DELETE /factors/:id 数据库异常', async () => {
    mockQuery.mockRejectedValueOnce(new Error('db error'));
    const res = await request(app).delete('/factors/1');
    expect([500, 404]).toContain(res.status);
  });

  test('GET /factors/tree 返回因子树', async () => {
    mockQuery.mockResolvedValueOnce([{ category: '风格' }]);
    mockQuery.mockResolvedValueOnce([{ id: 1, name: '因子A', description: '', type: 'base' }]);
    const res = await request(app).get('/factors/tree');
    expect(res.status).toBe(200);
    expect(res.body.data[0].title).toBe('风格');
    expect(res.body.data[0].children[0].title).toBe('因子A');
  });

  test('GET /factors/tree 数据库异常', async () => {
    mockQuery.mockRejectedValueOnce(new Error('db error'));
    const res = await request(app).get('/factors/tree');
    expect(res.status).toBe(500);
  });
}); 